package com.swingson;

import java.awt.Color;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JComponent;

/**
 * @author sad
 */
public class Utils {

    /**
     * input should be something like 
     */
    public static Color parseHexColor(String hexString) {
        int value = Integer.parseInt(hexString, 16);
        return new Color(value);
    }

    public static boolean isChild(Class child, Class parent) {
        try {
            child.asSubclass(parent);
            return true;
        } catch (ClassCastException ex) {
        }
        return false;
    }

    public static String makeFirstLetterBig(String string) {
        string = string.trim();
        if (string.length() == 0) {
            return string;
        }
        if (string.length() == 1) {
            return string.toUpperCase();
        }
        return string.substring(0, 1).toUpperCase() + string.substring(1);
    }

    public static String getComponentName(JComponent component) {
        if (component.getClientProperty("id") != null) {
            return (String) component.getClientProperty("id");
        }
        return component.getClass().getSimpleName();
    }

    public static String getClosestString(String originalString, Collection<String> strings) {
        String str = "";
        int minDist = 999999;
        for (String s : strings) {
            int distance = getLevenshteinDistance(originalString, s);
            if (distance < minDist) {
                minDist = distance;
                str = s;
            }
        }
        return str;
    }

    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
        if (s == null || t == null) {
            throw new IllegalArgumentException("Strings must not be null");
        }
        int n = s.length(); // length of s
        int m = t.length(); // length of t

        if (n == 0) {
            return m;
        } else if (m == 0) {
            return n;
        }

        if (n > m) {
            // swap the input strings to consume less memory
            CharSequence tmp = s;
            s = t;
            t = tmp;
            n = m;
            m = t.length();
        }

        int p[] = new int[n + 1]; //'previous' cost array, horizontally
        int d[] = new int[n + 1]; // cost array, horizontally
        int _d[]; //placeholder to assist in swapping p and d

        // indexes into strings s and t
        int i; // iterates through s
        int j; // iterates through t

        char t_j; // jth character of t

        int cost; // cost

        for (i = 0; i <= n; i++) {
            p[i] = i;
        }

        for (j = 1; j <= m; j++) {
            t_j = t.charAt(j - 1);
            d[0] = j;

            for (i = 1; i <= n; i++) {
                cost = s.charAt(i - 1) == t_j ? 0 : 1;
                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
                d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
            }

            // copy current distance counts to 'previous row' distance counts
            _d = p;
            p = d;
            d = _d;
        }

        // our last action in the above loop was to switch d and p, so p now
        // actually has the most recent cost counts
        return p[n];
    }

    public static Method getMethod(Class clazz, String methodName) {
        String id = clazz.getSimpleName() + "|" + methodName;
        if (methodAndClassNameToFieldObjectCache.containsKey(id)) {
            return methodAndClassNameToFieldObjectCache.get(id);
        }
        while (clazz != null) {
            Method method = searchMethodByName(clazz, methodName);
            if (method != null) {
                method.setAccessible(true);
                methodAndClassNameToFieldObjectCache.put(id, method);
                return method;
            }

            clazz = clazz.getSuperclass();
        }
        return null;
    }

    private static Method searchMethodByName(Class clazz, String name) {
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.getName().equals(name)) {
                return method;
            }
        }
        return null;
    }

    private static final Map<String, Method> methodAndClassNameToFieldObjectCache = new HashMap<String, Method>();

    /**
     Check if arguments of passed method are match to <b>arguments</b>
     */
    public static boolean checkMethodParameters(Method method, String errorMessage, Class... arguments) {
        if (method.getParameterTypes().length != arguments.length) {
            return false;
        }

        for (int i = 0; i < arguments.length; i++) {
            if (!Utils.isChild(method.getParameterTypes()[i],arguments[i])) {
                return false;
            }
        }
        return true;
    }

    public static String classArrayToString(Class... classes) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < classes.length; i++) {
            if (i != 0) {
                sb.append(", ");
            }
            sb.append(classes[i].getSimpleName());
        }
        sb.append("]");

        return sb.toString();
    }
}
